<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\database\container;

interface IConcrete
{
  public function isConnected();
  public function connect();
  public function disconnect();

  public function quote($value);

  //public function execute(\crcl\base\database\IQuery $oQuery, $aBind = []);

  public function createTable($sName, $aDefinition);
  public function droptable($sName);

  public function insert($sTable, $aData);

  public function update($sTable, $aData, $sWhere, $aBind = []);
  public function updateById($sTable, $aData, $id);

  public function delete($sTable, $sWhere, $aBind = []);
  public function deleteById($sTable, $id);

  public function select($sTable, $aFields, $sWhere, $aBind = []);
  public function selectById($sTable, $aFields, $id);

  public function getAsField($sField = \NULL);
  public function getAsRow();
  public function get();

  public function getLastQuery();
}

abstract class Base implements IConcrete
{
  public function __construct($sUri)
  {
    $this->sUri = $sUri;
    $this->oDsn = \crcl\base\Resource::reader($this->sUri);
  }

  public function isConnected()
  {
    return $this->bConnected;
  }

  //@codeCoverageIgnoreStart
  abstract function connect();
  abstract function disconnect();
  //@codeCoverageIgnoreEnd

  public function quote($value)
  {
    $oFilter = \crcl\base\Filter::quote();
    $value = $oFilter->filter($value);

    return $value;
  }

  //@codeCoverageIgnoreStart
  abstract function createTable($sName, $aDefinition);
  abstract function droptable($sName);
  //@codeCoverageIgnoreEnd

  public function getAsField($sField = \NULL)
  {
    $aData = $this->moveData();

    if (isset($aData[0]))
    {
      if (\is_null($sField))
      {
        if (\count($aData[0]) >= 1)
        {
          return \array_shift($aData[0]);
        }
      }
      else
        if (isset($aData[0][$sField]))
        {
          return $aData[0][$sField];
        }
    }
    throw new Exception('Missing data.',
      Exception::ERROR_MISSINGDATA,
      array('data' => $aData));
  }

  public function getAsRow()
  {
    $aData = $this->moveData();

    if (isset($aData[0]))
    {
      return $aData[0];
    }
    throw new Exception('Missing data.',
      Exception::ERROR_MISSINGDATA,
      array('data' => $aData));
  }

  public function get()
  {
    $aData = $this->moveData();

    if (!empty($aData))
    {
      return $aData;
    }
    throw new Exception('Missing data.',
      Exception::ERROR_MISSINGDATA,
      array('data' => $aData));
  }

  //@codeCoverageIgnoreStart
  abstract function insert($sTable, $aData);
  abstract function update($sTable, $aData, $sWhere, $aBind = []);
  abstract function updateById($sTable, $aData, $id);
  abstract function delete($sTable, $sWhere, $aBind = []);
  abstract function deleteById($sTable, $id);
  abstract function select($sTable, $aFields, $sWhere, $aBind = []);
  abstract function selectById($sTable, $aFields, $id);
  //@codeCoverageIgnoreEnd

  public function getLastQuery()
  {
    return $this->lastQuery;
  }


  /** PROTECTED ***********************************************************************************/

  protected $bConnected = \FALSE;

  protected $aData = array();
  protected $sUri;
  protected $oDsn;

  protected $lastQuery = \NULL;

  /** PRIVATE *************************************************************************************/

  private function moveData()
  {
    $aData = $this->aData;
    $this->aData = array();

    return $aData;
  }
}